<?php
/**
 * redis 缓存
 * zhouliang
 * 2020.09.04
 */

namespace App\Services\Tools;

use App\Enums\RedisKeyEnum;

class RedisService
{
    const KEY_ALL_CONFIG   = 'DB_CONFIG_DATA';
    const KEY_HEAD_PICTURE = 'u:hp:';
    const KEY_ROOM_CHAT    = 'room:chat:close';

    public static function getConfig()
    {
        return app('redis')->get(self::KEY_ALL_CONFIG);
    }

    public static function setConfig($config)
    {
        app('redis')->set(self::KEY_ALL_CONFIG, $config);
    }

    //获取正在使用的头像框
    public static function getHeadPicture($user_id)
    {
        return app('redis')->get(self::KEY_HEAD_PICTURE . $user_id);
    }

    //获取房间公屏状态 //1打开0关闭
    public static function getRoomChat($room_id)
    {
        $is_close = app('redis')->sismember(self::KEY_ROOM_CHAT, $room_id);

        return $is_close == 1 ? 0 : 1;
    }


    //添加好友关系
    public static function addFriend($user_id, $user_id_to)
    {
        $key = 'all:friends';
        if (!app('redis')->exists($key)) {
            self::initFriend();
        }
        $member = $user_id . '-' . $user_id_to;
        $member1 = $user_id_to . '-' . $user_id;
        app('redis')->sadd($key, $member);
        app('redis')->sadd($key, $member1);
    }


    //删除好友关系
    public static function delFriend($user_id, $user_id_to)
    {
        $key = 'all:friends';
        if (!app('redis')->exists($key)) {
            self::initFriend();
        }
        $member = $user_id . '-' . $user_id_to;
        $member1 = $user_id_to . '-' . $user_id;
        app('redis')->srem($key, $member);
        app('redis')->srem($key, $member1);
    }


    //查询好友关系(初始化,不存在key值时初始化)
    public static function initFriend()
    {
        $key = 'all:friends';
        $list = app('model_friend')->select('user_id', 'friend_id')->get()->toArray();

        //mysql的M方法
        $result = [];
        foreach ($list as $value) {
            $k = $value['user_id'] . '-' . $value['friend_id'];
            $result[$k] = 1;
        }
        $all_friend = array_keys($result);
        app('redis')->sadd($key, ...$all_friend);
    }


    /**
     * 根据room_id获取单个房间的人气值
     *
     * @param  int  $room_id
     * @return int|number
     */
    public static function getPopularityByRoomId($room_id = 0)
    {
        $roomPopularity = 0;
        $time = time();
        $pattern = 'popu:r:' . $room_id;  //非模糊匹配,准确搜索

        //查询符合条件的集合数组
        $keys_arr = app('redis')->zrangebyscore($pattern, $time, "+inf");
        if (!empty($keys_arr)) {
            $val_list = app('redis')->mget($keys_arr);  //查询不到返回false
            if ($val_list) {
                $roomPopularity = array_sum($val_list);
            }
        }

        return $roomPopularity;
    }

    /**
     * 根据room_ids返回人气数组
     *
     * @param  array  $room_ids
     * @return array
     */
    public static function getPopularityArr($room_ids = [])
    {
        $popularityArr = [];
        foreach ($room_ids as $val) {
            $popularityArr[$val] = self::getPopularityByRoomId($val);
        }

        return $popularityArr;
    }


    /**
     * 清除相关key值
     *
     * @param $room_id
     * @param $uid
     * @param  int  $type
     * @return bool
     */
    public static function clearPopularityByKey($room_id, $uid, $type = 1)
    {
        if ($type == 1) {
            //加入房间的类别直接删除处理
            $sign_key = 'popu:join:k' . $room_id . $uid;
            $key = app('redis')->get($sign_key);

            if (isset($key) && !empty($key)) {
                $room_key = 'popu:r:' . $room_id;
                app('redis')->zrem($room_key, $key);
                app('redis')->del($key);
                app('redis')->del($sign_key);
                $roomPopularity = self::getPopularityByRoomId($room_id);

                //发送消息更新人气
                $push = new PushService(0, $room_id);
                $push->updatePopularity($roomPopularity);

                return $roomPopularity;
            }
        }
        $pattern = 'popu:p:' . $room_id . 't' . $type . 'u' . $uid . "*";
        $keys_arr = app('redis')->keys($pattern);
        $room_key = 'popu:r:' . $room_id;
        if (!empty($keys_arr)) {
            foreach ($keys_arr as $val) {
                app('redis')->zrem($room_key, $val);
                app('redis')->del($val);
            }
        }
        $roomPopularity = self::getPopularityByRoomId($room_id);

        //发送消息更新人气
        $push = new PushService(0, $room_id);
        $push->updatePopularity($roomPopularity);

        return $roomPopularity;
    }


    /**
     * 获取所有房间ID人气值数组(已废弃)
     *
     * @return array
     */
    public static function getAllRoomPopuArr()
    {
        $pattern = 'popu:r:*';
        $keys_arr = app('redis')->keys($pattern);

        $room_ids = [];

        if ($keys_arr) {
            foreach ($keys_arr as $val) {
                $room_ids[] = substr($val, 7);
            }
        }

        $popularity_arr = self::getPopularityArr($room_ids);

        $popularity_arr = array_filter($popularity_arr);

        arsort($popularity_arr);

        app('redis')->set('popu:list', $popularity_arr);

        return $popularity_arr;
    }

    /**
     * 获取所有房间ID人气值数组
     *
     * @return array
     */
    public static function getNewAllRoomPopuArr()
    {
        $popuListStr = app('redis')->get('popu:list');
        if (!empty($popuListStr)) {
            return json_decode($popuListStr, 1);
        }

        $pattern = 'popu:r:*';
        $keys_arr = app('redis')->keys($pattern);

        $room_ids = [];

        if ($keys_arr) {
            foreach ($keys_arr as $val) {
                $room_ids[] = substr($val, 7);
            }
        }

        $popularity_arr = self::getPopularityArr($room_ids);

        $popularity_arr = array_filter($popularity_arr);

        arsort($popularity_arr);

        app('redis')->set('popu:list', json_encode($popularity_arr));

        app('redis')->expire('popu:list', 600);

        return $popularity_arr;
    }

    //-------------新的人气处理逻辑模块,废弃原有的两张表,废弃user_room和room_join的popularity字段,全部走redis string存储----------------

    /**
     * 增加人气记录
     *
     * @param $room_id  (房间编号)
     * @param $popularity  (人气值)
     * @param  int  $type  1用户进入房间2送房间礼物3送背包礼物4周星榜人气5管理后台赠送人气6活动赠送7竞拍成功8点歌增加人气9单人房点击红心增加人气
     * @param  int  $expired_time  (过期时间(1设置默认时间为7天,其余类型具体设置过期时间)默认3天
     * @param  int  $sign  (可扩展用于各种类型,一期只用于销毁用户退出人气减少)
     * @return int|number   返回人气值
     */
    public static function setPopularityCache($room_id, $popularity, $type = 1, $expired_time = 259200, $sign = 0)
    {
        //开启事务存储room_id和popularity_value,暂不对异常处理
        app('redis')->multi();

        $time = time();

        $key = uniqid('popu:p:' . $room_id . 't' . $type . 'u' . $sign . 'd' . $time, true);

        $end_time = $time + $expired_time;

        if ($type == 1) {
            //用户加入房间涨人气的,记录一个roomid+uid绑定的key值
            $sign_key = 'popu:join:k' . $room_id . $sign;
            app('redis')->set($sign_key, $key);
        }

        app('redis')->setex($key, $expired_time, $popularity);

        $roomset_key = 'popu:r:' . $room_id;

        app('redis')->zadd($roomset_key, $end_time, $key);

        //记录日志
        //        $data = [
        //            'room_id'     => $room_id,
        //            'popularity'  => $popularity,
        //            'type'        => 1,
        //            'start_at'    => $time,
        //            'end_at'      => $time + $expired_time,
        //            'expire_time' => $expired_time,
        //            'sign'        => $sign,
        //        ];
        //
        //        $log_key = uniqid("popu:log:" . date('YmdHis', time()) . 'r' . $room_id . $type, true);
        //        app('redis')->set($log_key, json_encode($data));

        $status = app('redis')->exec();

        if (!$status) {
            app('redis')->discard();
        }   //异常回滚

        $roomPopularity = self::getPopularityByRoomId($room_id);

        //发送消息
        (new PushService(0, $room_id))->updatePopularity($roomPopularity);

        return $roomPopularity;
    }


    /**
     * 获取缓存的id数组
     *
     * @return array
     */
    public static function getPopuList()
    {
        $list = app('redis')->get('popu:list');

        $list = $list ? $list : [];

        return $list;
    }

    //设置用户在线
    public static function setOnline($room_id, $user_id)
    {
        $key = 'room:online:' . $room_id;
        if (!app('redis')->exists($key)) {
            $users = app('model_room_join')->getOnlineUserList($room_id);
            if (!$users) {
                app('redis')->sadd($key, ...$users);
            }
        }
        app('redis')->sadd($key, $user_id);
    }

    //设置用户下线
    public static function setOffline($room_id, $user_id)
    {
        $key = 'room:online:' . $room_id;
        $result = app('redis')->srem($key, $user_id);

        return $result > 0 ? 1 : 0;
    }

    //获取麦位上的用户
    public static function getPit($room_id, $pit)
    {
        $user_id = app('redis')->hget('room:' . $room_id, 'pit' . $pit);

        return $user_id > 0 ? $user_id : 0;
    }

    //设置麦位上的用户
    public static function setPit($room_id, $pit, $user_id)
    {
        app('redis')->hset('room:' . $room_id, 'pit' . $pit, $user_id);
    }

    public static function getChatRooms($room_id)
    {
        $key = 'all:chatrooms';
        if (!app('redis')->exists($key)) {
            $list = app('model_user_room')->orderBy('id', 'asc')->select('id', 'chatrooms')->get();
            if ($list) {
                $list = $list->toArray();
                $all = array_column($list, 'chatrooms', 'id');
                app('redis')->hmset($key, $all);
            }
        }
        $chatrooms = app('redis')->hget($key, $room_id);

        return $chatrooms;
    }

    public static function getGradeConfig()
    {
        $key = 'grade:config';
        $list = app('redis')->get($key);
        if (!$list) {
            $list = app('model_grade_config')->orderBy('id', 'asc')->select('id', 'grade', 'experience',
                'head_picture')->get()->keyBy('id')->toJson();
            app('redis')->set($key, $list);
        }

        return json_decode($list, true);
    }

    public static function getNobilityConfig($nobility = '')
    {
        $key = 'nobility:config';
        $list = app('redis')->get($key);
        if (!$list) {
            $list = app('model_nobility')->orderBy('id', 'asc')->get()->keyBy('id')->toJson();
            app('redis')->set($key, $list);
        }

        $list = json_decode($list, true);
        if ($nobility) {
            if (!isset($list[$nobility])) { //爵位等级不存在取最大的爵位
                $nobilityIndex = max(...array_keys($list));
                $nobilityConf = $list[$nobilityIndex];
            } else {
                $nobilityConf = $list[$nobility];
            }

            return $nobilityConf;
        }

        return $list;
    }

    public static function getUserRegTime($user_id)
    {
        $key = 'u:reg:time:' . $user_id;
        $register_time = app('redis')->get($key);
        if (!$register_time) {
            $register_time = app('model_user')->where(['user_id' => $user_id])->value('register_time');
            app('redis')->set($key, $register_time);
        }

        return $register_time;
    }

    //关闭|打开公屏 status:1打开0关闭
    public static function setRoomChat($room_id, $status = 1)
    {
        $key = 'room:chat:close';
        if ($status == 1) {
            app('redis')->srem($key, $room_id);
        } else {
            app('redis')->sadd($key, $room_id);
        }
    }

    public static function getUserMixer($room_id, $user_id)
    {
        $key = 'mixer:' . $room_id . ':' . $user_id;
        $id = app('redis')->get($key);

        return $id > 0 ? $id : 0;
    }

    public static function setUserMixer($room_id, $user_id, $id)
    {
        $key = 'mixer:' . $room_id . ':' . $user_id;
        $id = $id > 0 ? $id : 0;
        app('redis')->set($key, $id);
    }

    public static function getUserWithdrawTimes($user_id)
    {
        $key = 'u:w:t:' . $user_id;
        $times = app('redis')->get($key);
        if ($times <= 0) {
            $times = 0;
        }

        return $times;
    }

    public static function incUserWithdrawTimes($user_id)
    {
        $key = 'u:w:t:' . $user_id;
        app('redis')->incr($key);

        app('redis')->expire($key, todayLeftTime());
    }

    //设置申请上麦的人数
    public static function setApplyWheatCount($room_id, $count = 1)
    {
        $result = app('redis')->hincrby('room:' . $room_id, 'a:c', $count);
        if ($result < 0) {
            app('redis')->hset('room:' . $room_id, 'a:c', 0);
        }
    }

    //获取申请上麦的人数
    public static function applyWheatCount($room_id)
    {
        $count = app('model_room_pit_apply')->where(['room_id' => $room_id])->count();

        return $count > 0 ? $count : 0;
    }

    //获取用户在线状态
    public static function online($room_id, $user_id)
    {
        $key = 'room:online:' . $room_id;
        $result = app('redis')->sismember($key, $user_id);

        return $result ? 1 : 0;
    }

    //type:1普通房引导2拍卖房引导3相亲房引导
    public static function checkGuide($user_id, $type = 1)
    {
        switch ($type) {
            case 2:
                $key = 'guide:user:auction';
                break;
            case 3:
                $key = 'guide:user:dating';
                break;
            default:
                $key = 'guide:user';
        }
        if (!app('redis')->exists($key)) {
            $where['type'] = $type;
            $lists = app('model_room_guide')->where($where)->pluck('user_id');
            if ($lists->isEmpty()) {
                $lists = [0 => 0];
            }
            app('redis')->sadd($key, ...$lists);
        }

        return app('redis')->sismember($key, $user_id) ? 1 : 0;
    }

    public static function addGuideUser($user_id, $type = 1)
    {
        switch ($type) {
            case 2:
                $key = 'guide:user:auction';
                break;
            case 3:
                $key = 'guide:user:dating';
                break;
            default:
                $key = 'guide:user';
        }
        app('redis')->sadd($key, $user_id);
    }

    public static function getRide($user_id)
    {
        $key = 'u:ride:' . $user_id;
        $result = app('redis')->get($key);
        if ($result) {
            return json_decode($result, true);
        }

        return null;
    }

    //个性装扮：进场特效
    public static function getJoinSpecial($user_id)
    {
        $key = 'u:join:special:' . $user_id;
        $result = app('redis')->get($key);
        if ($result) {
            return json_decode($result, true);
        }

        return null;
    }

    /**
     * 判断是否是房间管理员
     *
     * @param $room_id
     * @param $user_id
     * @return
     */
    public static function checkRoomManager($room_id, $user_id)
    {
        $key = 'room:manager:' . $room_id;
        if (!app('redis')->exists($key)) {
            $list = app('model_room_join')->where(['manager' => 1, 'room_id' => $room_id])->pluck('user_id');
            if (!$list->isEmpty()) {
                $list = $list->toArray();
                app('redis')->sadd($key, ...$list);
            }
        }

        return app('redis')->sismember($key, $user_id);
    }

    /**
     * 判断是否是房主
     *
     * @param $room_id
     * @param $user_id
     * @return bool
     */
    public static function checkRoomOwner($room_id, $user_id)
    {
        $key = 'room:owner:' . $room_id;
        $owner = app('redis')->get($key);
        if (!$owner) {
            $owner = app('model_user_room')->where(['id' => $room_id])->value('user_id');
            app('redis')->set($key, $owner);
        }

        return $owner == $user_id;
    }

    /**
     * 获取用户系统设置
     *
     * @param $user_id
     * @return bool
     */
    public static function getUserConfig($user_id)
    {
        $key = 'user:config:' . $user_id;
        if (app('redis')->exists($key)) {
            $result = app('redis')->get($key);

            return json_decode($result, true);
        } else {
            $userConfig = app('model_user_config')->where('user_id', $user_id)->first();
            if (!empty($userConfig)) {
                app('redis')->set($key, json_encode($userConfig->toArray()));
            }

            return $userConfig->toArray();
        }

        return null;
    }

    /**
     * @param $userId
     * @return mixed
     */
    public static function upUserConfig($userId)
    {
        $key = 'user:config:' . $userId;
        $res = app('model_user_config')->where('user_id', $userId)->first()->toArray();
        $result = app('redis')->set($key, json_encode($res));//让配置立即生效

        return boolval($result);
    }

    public static function getAllAuctionRecord($auction_id)
    {
        $key = 'auction:' . $auction_id;
        if (!app('redis')->exists($key)) {
            $list = app('model_auction_record')->selectRaw('max(total_cost) as total_cost,user_id')->where('auction_id', $auction_id)->orderBy('total_cost', 'desc')->groupBy('user_id')->get();
            if (!$list->isEmpty()) {
                $data = array_column($list->toArray(), 'total_cost', 'user_id');
                app('redis')->zadd($key, $data);
            }
        }

        return app('redis')->zrevrange($key, 0, -1, "WITHSCORES");
    }

    public static function getLastAuctionRecord($auction_id)
    {
        $all_record = self::getAllAuctionRecord($auction_id);
        if (empty($all_record)) {
            return [];
        }

        return array_slice($all_record, 0, 1, true);
    }

    public static function addUserGiftWall($user_id, $gift_id)
    {
        $redis_key = 'u:g:w:' . $user_id;
        if (!app('redis')->exists($redis_key)) {
            self::initUserGiftWall($user_id);
        }

        return app('redis')->sadd($redis_key, $gift_id);
    }

    public static function initUserGiftWall($user_id)
    {
        $redis_key = 'u:g:w:' . $user_id;
        app('redis')->del($redis_key);
        $list = app('model_give_gift')->where('gift_user', $user_id)->selectRaw('sum(number) as total,gift_id,min(add_time) add_time')->groupBy('gift_id')->get();
        if ($list) {
            app('model_user_gift_wall')->where(['user_id' => $user_id])->delete();
            $data = [];
            foreach ($list as $key => $value) {
                app('redis')->sadd($redis_key, $value->gift_id);
                $data[] = [
                    'user_id'  => $user_id,
                    'gift_id'  => $value->gift_id,
                    'get_time' => $value->add_time,
                    'number'   => $value->total,
                ];
            }
            app('model_user_gift_wall')->insert($data);
        } else {
            app('redis')->sadd($redis_key, 0);
        }
    }

    public function getCurrentWeekStarGift()
    {
        $weeks = date('oW');
        $key = 'weekstar:gift:' . $weeks;
        if (app('redis')->exists($key)) {
            return app('redis')->hgetall($key);
        } else {
            $result = M('WeekStar')->where(['weeks' => $weeks, 'deleted' => 0])->find();
            app('redis')->hmset($key, $result);
            app('redis')->expire($key, Helper::todayLeftTime());

            return $result;
        }
    }

    public function addWeekStarData($data)
    {
        $week_star_gift = $this->getCurrentWeekStarGift();
        if (!$week_star_gift) {
            return false;
        }
        $total = $data['total_price'];
        if ($total <= 0) {
            return false;
        }

        if (!in_array($data['gift_id'], [$week_star_gift['gift_id_1'], $week_star_gift['gift_id_2']])) {
            return false;
        }

        $room_id = $data['room_id'];
        $weeks = date('oW');
        if ($room_id > 0) {
            $key_room = 'weekstar:room:' . $weeks;
            app('redis')->zincrby($key_room, $total, $room_id);
        }
        $key_rich = 'weekstar:rich:' . $weeks;
        $key_charm = 'weekstar:charm:' . $weeks;
        app('redis')->zincrby($key_rich, $total, $data['user_id']);
        app('redis')->zincrby($key_charm, $total, $data['gift_user']);
    }

    public static function getAllNobilityUsers()
    {
        $key = 'nobility:users';
        $result = app('redis')->hgetall($key);
        if (!$result) {
            $nobility_users = app('model_user')->where('nobility', '>', 0)->where('deleted', 0)->pluck('nobility,user_id');
            if (!$nobility_users->isEmpty()) {
                $result = $nobility_users->toArray();
            } else {
                $result = [0 => 0];
            }
            app('redis')->hmset($key, $result);
        }

        return $result;
    }

    public static function getUserNobilityValue($user_id, $key)
    {
        $all_nobility_users = self::getAllNobilityUsers();
        $nobility_id = $all_nobility_users[$user_id] ?? 0;
        $nobility_config = self::getNobilityConfig();

        return $nobility_config[$nobility_id][$key] ?? '';
    }

    public static function getQuestion()
    {
        $redis_key = 'all:question';
        if (app('redis')->exists($redis_key)) {
            return app('redis')->smembers($redis_key);
        }
        $all_question = app('model_qa_question')->pluck('id');
        if (!$all_question->isEmpty()) {
            $data = $all_question->toArray();
        } else {
            $data = [0 => 0];
        }
        app('redis')->sadd($redis_key, ...$data);

        return $data;
    }

    public static function getDatingQuestion($dating_id)
    {
        $redis_key = 'dating:question:' . $dating_id;
        if (app('redis')->exists($redis_key)) {
            return app('redis')->smembers($redis_key);
        }
        $all_question = self::getQuestion();
        app('redis')->sadd($redis_key, ...$all_question);

        return $all_question;
    }

    public static function getRandDatingQuestion($dating_id, $count = 5)
    {
        $redis_key = 'dating:question:' . $dating_id;
        $result = app('redis')->spop($redis_key, $count);
        if (count($result) < $count) {
            app('redis')->del($redis_key);
            self::getDatingQuestion($dating_id);
            $result = self::getRandDatingQuestion($dating_id, $count);
        }

        return $result;
    }

    // 删除用户信息缓存
    public static function clearUserInfo($user_id)
    {
        $key = sprintf(RedisKeyEnum::USER_INFO, $user_id);
        app('redis')->del($key);
    }
    //设置用户爵位等级
    public static function setUserNobility($user_id, $nobility_id)
    {
        $key = 'nobility:users';
        app('redis')->hset($key, $user_id, $nobility_id);
    }

    // 获取用户信息
    public static function getUserBaseInfo($user_id, $field = '', $isBase = false)
    {
        $key = sprintf(RedisKeyEnum::USER_INFO, $user_id);
        if (!app('redis')->exists($key)) {
            $userInfo = app('repo_user_data')->getBaseUserInfo($user_id);
            if (!$userInfo) {
                return null;
            }
            $data = [
                'user_id'          => $user_id,
                'role'             => $userInfo['role'] ?? 1,    // 角色
                'register_time'    => $userInfo['register_time'], // 注册时间
                'rank_id'          => $userInfo['rank_id'] ?? 0, // vip登记
                'nobility'         => $userInfo['nobility'] ?? 0, // 爵位id
                'user_code'        => $userInfo['user_code'] ?? '',
                'sex'              => $userInfo['sex'] ?? 0, // 性别
                'head_picture'     => $userInfo['head_picture'] ?? '', // 头像
                'nickname'         => $userInfo['nickname'] ?? '', // 昵称
                'ry_token'         => $userInfo['ry_token'] ?? '', // 融云token
                'channel_stage_id' => $userInfo['channel_stage_id'] ?? '', //渠道分期id
                'new_love_title' => $userInfo['new_love_title'] ?? '',   //新恋爱类型名称
                'new_love_icon' => $userInfo['new_love_icon'] ?? '',     //新恋爱类型图标
            ];
            app('redis')->hmset($key, $data);
        } else {
            $data = app('redis')->hgetall($key);
        }
        if (!$isBase) {
            $rank_id = $data['rank_id'] ?? 0;
            $nobility_id = $data['nobility'] ?? 0;
            $grade_info = app('model_grade_config')->getGradeConfig($rank_id);
            $nobility_info = app('model_nobility')->getNobilityInfo($nobility_id);

            $data['rank_icon'] = $grade_info['head_picture'] ?? '';
            $data['rank_screen_img'] = $grade_info['screen_img'] ?? '';
            $data['rank_name'] = $grade_info['grade'] ?? '';
            $data['moods'] = $nobility_info['moods'] ?? 10;
            $data['nobility_id'] = $nobility_info['id'] ?? '';
            $data['nobility_name'] = $nobility_info['name'] ?? '';
            $data['nobility_icon'] = $nobility_info['head_picture'] ?? '';
            $isNew = 0;
            $register_time = $data['register_time'] ?? 0;
            if ($register_time >= (time() - 3 * 86400)) { // 天
                $isNew = 1;
            }
            $data['user_is_new'] = $isNew;
            // 实时用户正在使用的头像框
            $data['dress_picture'] = RedisService::getHeadPicture($user_id); //头像框
        }
        if ($field) {
            return $data[$field] ?? '';
        }

        return $data;
    }
}
